package com.eatme.web.security.config;


import com.eatme.web.common.vo.AppResponse;
import com.eatme.web.common.vo.ResponseCode;
import com.eatme.web.security.authentication.domain.entity.SecurityUser;
import com.eatme.web.security.authentication.emailcode.filter.EmailCodeAuthenticationFilter;
import com.eatme.web.security.authentication.emailcode.provider.EmailCodeAuthenticationProvider;
import com.eatme.web.security.authentication.emailcode.service.impl.EmailCodeSecurityUserServiceImpl;
import com.eatme.web.security.authentication.password.filter.RestAuthenticationFilter;
import com.eatme.web.security.authentication.password.provider.RestAuthenticationProvider;
import com.eatme.web.security.authentication.password.service.impl.UserPasswordSecurityUserServiceImpl;
import com.eatme.web.security.authentication.phonecode.filter.PhoneCodeAuthenticationFilter;
import com.eatme.web.security.authentication.phonecode.provider.PhoneCodeAuthenticationProvider;
import com.eatme.web.security.authentication.phonecode.service.impl.PhoneCodeSecurityUserServiceImpl;
import com.eatme.web.security.authentication.wechat.applet.authentication.WechatAppletAuthenticationToken;
import com.eatme.web.security.authentication.wechat.applet.filter.WechatAppletAuthenticationFilter;
import com.eatme.web.security.authentication.wechat.applet.provider.WechatAppletAuthenticationProvider;
import com.eatme.web.security.authentication.wechat.applet.service.impl.WechatAppletSecurityUserServiceImpl;
import com.eatme.web.security.jwt.filter.JwtAuthenticationFilter;
import com.eatme.web.util.jwt.NimbusJoseJwtUtil;
import com.eatme.web.util.wechat.WXBaseService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2WeChatMiniProgramAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.web.authentication.*;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

@Configuration
@EnableWebSecurity    // 添加 security 过滤器
@EnableGlobalMethodSecurity(prePostEnabled = true)	// 启用方法级别的权限认证
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(SecurityConfiguration.class);

    private final ObjectMapper objectMapper;

    private final SecurityProblemSupport securityProblemSupport;

    private final JwtAuthenticationFilter jwtFilter;

    private final NimbusJoseJwtUtil nimbusJoseJwtUtil;

    private final EmailCodeSecurityUserServiceImpl emailCodeUserDetailsServiceImpl;

    private final PhoneCodeSecurityUserServiceImpl phoneCodeSecurityUserServiceImpl;

    private final WechatAppletSecurityUserServiceImpl wechatAppletSecurityUserServiceImpl;

    private final UserPasswordSecurityUserServiceImpl usernamePasswordSecurityUserServiceImpl;

    private final WXBaseService wXBaseService;


    public SecurityConfiguration(ObjectMapper objectMapper,
                                 SecurityProblemSupport securityProblemSupport,
                                 JwtAuthenticationFilter jwtFilter,
                                 EmailCodeSecurityUserServiceImpl emailCodeUserDetailsServiceImpl,
                                 PhoneCodeSecurityUserServiceImpl phoneCodeSecurityUserServiceImpl,
                                 WechatAppletSecurityUserServiceImpl wechatAppletSecurityUserServiceImpl,
                                 UserPasswordSecurityUserServiceImpl usernamePasswordSecurityUserServiceImpl,
                                 WXBaseService wXBaseService,
                                 NimbusJoseJwtUtil nimbusJoseJwtUtil) {
        this.objectMapper = objectMapper;
        this.securityProblemSupport = securityProblemSupport;
        this.jwtFilter = jwtFilter;
        this.emailCodeUserDetailsServiceImpl = emailCodeUserDetailsServiceImpl;
        this.phoneCodeSecurityUserServiceImpl = phoneCodeSecurityUserServiceImpl;
        this.wechatAppletSecurityUserServiceImpl = wechatAppletSecurityUserServiceImpl;
        this.usernamePasswordSecurityUserServiceImpl = usernamePasswordSecurityUserServiceImpl;
        this.wXBaseService = wXBaseService;
        this.nimbusJoseJwtUtil= nimbusJoseJwtUtil;
    }

    /**
     * Spring Security 配置
     * <p>
     * 详细使用说明参见：
     * <p>
     * <a href=
     * "https://gitee.com/xuxiaowei-cloud/xuxiaowei-cloud/blob/main/passport/src/main/java/cloud/xuxiaowei/passport/configuration/AuthorizationServerConfiguration.java">Gitee</a>
     * <p>
     * <a href=
     * "https://github.com/xuxiaowei-cloud/xuxiaowei-cloud/blob/main/passport/src/main/java/cloud/xuxiaowei/passport/configuration/AuthorizationServerConfiguration.java">Github</a>
     *
     * @author xuxiaowei
     * @since 0.0.1
     */
    @Configuration
    public class WebSecurityConfigurerAdapterConfiguration {

        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {

            // 此段代码来自：OAuth2AuthorizationServerConfiguration#applyDefaultSecurity(HttpSecurity)
            OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
                    new OAuth2AuthorizationServerConfigurer();
            RequestMatcher endpointsMatcher = authorizationServerConfigurer
                    .getEndpointsMatcher();
            http
                    .requestMatcher(endpointsMatcher)
                    .authorizeRequests(authorizeRequests ->
                            authorizeRequests.anyRequest().authenticated()
                    )
                    .csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
                    .apply(authorizationServerConfigurer);

            // 开启 http://localhost:1301/.well-known/openid-configuration
            authorizationServerConfigurer.oidc(Customizer.withDefaults());

            // authorizationServerConfigurer.registeredClientRepository(registeredClientRepository());
            // 自定义客户授权
            authorizationServerConfigurer.tokenEndpoint(tokenEndpointCustomizer -> tokenEndpointCustomizer
                            .accessTokenRequestConverter(new DelegatingAuthenticationConverter(Arrays.asList(
                                    // 新增：微信 OAuth2 用于验证授权授予的 {@link
                                    // OAuth2WeChatMiniProgramAuthenticationToken}
                                    new OAuth2WeChatMiniProgramAuthenticationConverter(),
                                    // 默认值：OAuth2 授权码认证转换器
                                    new OAuth2AuthorizationCodeAuthenticationConverter(),
                                    // 默认值：OAuth2 刷新令牌认证转换器
                                    new OAuth2RefreshTokenAuthenticationConverter(),
                                    // 默认值：OAuth2 客户端凭据身份验证转换器
                                    new OAuth2ClientCredentialsAuthenticationConverter()))
                            )
                    // 用于处理失败的身份验证尝试的策略。
                    // .errorResponseHandler(new AccessTokenAuthenticationFailureHandlerImpl())
            );

            // 微信小程序 OAuth2 身份验证提供程序
            new OAuth2WeChatMiniProgramAuthenticationProvider(http);

            return http.build();
        }

    }


    /**
     *  用于身份验证的 Spring Security 过滤器链
     * @param authenticationManager {@link AuthenticationManager}
     * @param http {@link HttpSecurity}
     * @return {@link SecurityFilterChain}
     * @throws Exception {@link Exception} 安全认证异常
     */
    @Bean
    @Order(1)
    public SecurityFilterChain defaultSecurityFilterChain(@Qualifier("authenticationManager") AuthenticationManager authenticationManager,HttpSecurity http) throws Exception {
        return http
                // 禁用basic 明文验证
                // .httpBasic(withDefaults())
                .httpBasic().disable()
                 // 禁用默认登录页面
                // .formLogin().disable()
                .formLogin(Customizer.withDefaults())
//                .formLogin(formLogin-> formLogin
//                                .loginProcessingUrl("/login")
//                                .successHandler(new AuthenticationSuccessHandler() {
//                                    @Override
//                                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//                                        response.setStatus(HttpStatus.OK.value());
//                                        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
//                                        response.setCharacterEncoding("UTF-8");
//                                        authentication.getPrincipal();
//                                        SecurityUser user = (SecurityUser) authentication.getPrincipal();
//                                        LOG.info("SecurityUser: {}",user);
//                                        user.setAccessToken(nimbusJoseJwtUtil.createAccessToken(user));
//                                        user.setRefreshToken(nimbusJoseJwtUtil.createRefreshToken(user));
//                                        if (authentication instanceof WechatAppletAuthenticationToken) {
//                                            WechatAppletAuthenticationToken authenticationToken = (WechatAppletAuthenticationToken) authentication;
//                                            user.setSession_key(authenticationToken.getSession_key());
//                                        }
//                                        response.getWriter().println(objectMapper.writeValueAsString(AppResponse.ok(user)));
//                                        LOG.info("认证成功");
//                                    }
//                                })
//                                .failureHandler(new AuthenticationFailureHandler() {
//                                    @Override
//                                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//                                        LOG.info("认证失败,原因是: {}",exception);
//                                        response.setStatus(HttpStatus.UNAUTHORIZED.value());
//                                        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
//                                        response.setCharacterEncoding("UTF-8");
//                                        AppResponse appResponse;
//                                        if (exception instanceof LockedException) {
//                                            appResponse = AppResponse.setResult(ResponseCode.LOCKED_ACCOUNT);
//                                        } else if(exception instanceof DisabledException) {
//                                            appResponse = AppResponse.setResult(ResponseCode.DISABLED_ACCOUNT);
//                                        } else {
//                                            appResponse = AppResponse.setResult(ResponseCode.AUTHORIZATION).message(exception.getMessage());
//                                        }
//                                        response.getWriter().println(objectMapper.writeValueAsString(appResponse));
//                                    }
//                                })
//
//                )
                .logout(logout -> logout
                        .logoutUrl("/user/logout")
                        .invalidateHttpSession(true)
                        .deleteCookies("remember-me")
                        .logoutSuccessHandler(jsonLogoutSuccessHandler())
                )
                //invalidSessionStrategy: 会话失效策略

//                .sessionManagement(session->
//                        session.invalidSessionStrategy(
//                        new InvalidSessionStrategy() {
//                            @Override
//                            public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
//                                response.setContentType("text/html;chartset=UTF-8");
//                                response.getWriter().write("绘画失效");
//                            }
//                        }
//                ))

                // State-less session (state in access-token only)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

//                .sessionManagement((sessionManagement) ->
//                        sessionManagement.maximumSessions(1)
//                                .sessionRegistry(sessionRegistry())
//                )

                // 设置异常的EntryPoint，如果不设置，默认使用Http403ForbiddenEntryPoint

//                .exceptionHandling(exception->exception.authenticationEntryPoint(invalidAuthenticationEntryPoint))


                .exceptionHandling(exception -> exception
                        .authenticationEntryPoint(securityProblemSupport)
                        .accessDeniedHandler(securityProblemSupport))


//                .exceptionHandling(exception ->exception.accessDeniedHandler(new AccessDeniedHandler() {
//                    @Override
//                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
//                        LOG.info("访问被拒绝,原因是: {}",accessDeniedException);
//                        accessDeniedException.printStackTrace();
//                    }
//                }))

//                .rememberMe(e->
//                        e.rememberMeParameter("remember-me")
//                                .rememberMeCookieDomain("")
//                                .tokenRepository()
////                                .key("test")
//                )
                .requestMatchers(request -> request.mvcMatchers("/**"))

//                .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
//                        // 允许所有OPTIONS请求
//                        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
//                        // 允许直接访问授权登录接口
//                        .requestMatchers(HttpMethod.POST, "/web/authenticate").permitAll()
//                        // 允许 SpringMVC 的默认错误地址匿名访问
//                        .requestMatchers("/error").permitAll()
//                        // 其他所有接口必须有Authority信息，Authority在登录成功后的UserDetailsImpl对象中默认设置“ROLE_USER”
//                        //.requestMatchers("/**").hasAnyAuthority("ROLE_USER")
//                        // 允许任意请求被已登录用户访问，不检查Authority
//                        .anyRequest().authenticated())

                .authorizeRequests(authorizeRequests ->
                                        authorizeRequests.antMatchers(
                                                        // 放行不需要认证
                                                "/applet/login",
                                                        "/email/login",
                                                        "/user/login",
                                                        "/user/token",
                                                        "/user/refresh",
                                                        "/user/logout",
                                                        "/druid/**",
                                                        "/template/**",
                                                        "/sys/job/**",
                                                        "/user/**",
                                                        "/oauth/**",
                                                        "/oauth2/**",
                                                "captcha/*"
                                                ).permitAll()
                                                // 所有请求都必须认证才能访问,必须登录
                                                .anyRequest().authenticated())
                //将JWT拦截器添加到UsernamePasswordAuthenticationFilter之前
                //登录之前验证token 从token中获取到登录凭证
                //.addFilterBefore(jwtFilter,UsernamePasswordAuthenticationFilter.class)

                //重写登录
                // 替代过滤器
                //.addFilterAt(restAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)

                // 邮箱验证码登录
                //.addFilterBefore(emailCodeAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)

                // 手机验证码登录
                //.addFilterBefore(phoneCodeAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)

//                // 微信验证登录
                //.addFilterBefore(wechatAppletAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)

                // .oauth2Login(withDefaults())
                // .openidLogin()
                // Customizer.withDefaults(): 关闭
                // http.csrf(Customizer.withDefaults()); // 跨域漏洞防御:关闭
                // http.csrf(csrf -> csrf.disable())
                // http.csrf(csrf -> csrf.disable()); //相当于 http.csrf(Customizer.withDefaults());
                // .csrf(withDefaults()) // 封装的太过于抽象比较难以阅读代码
                // .csrf(csrf -> csrf.disable())
                .csrf(CsrfConfigurer::disable)

                //.cors(CorsConfigurer::disable)
                // .cors(cors->cors.configurationSource())

                //https only
                //.requiresChannel(channel->channel.anyRequest().requiresSecure())

                //.oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver()

                .build();
    }

    private RestAuthenticationFilter restAuthenticationFilter(AuthenticationManager authenticationManager) {
        RestAuthenticationFilter filter = new RestAuthenticationFilter(objectMapper);
        // 登录成功处理
        filter.setAuthenticationSuccessHandler(jsonAuthenticationSuccessHandler());
        // 登陆失败处理
        filter.setAuthenticationFailureHandler(jsonAuthenticationFailureHandler());
        filter.setAuthenticationManager(authenticationManager);
        filter.setFilterProcessesUrl("/user/login");
        // filter.setAuthenticationDetailsSource();
        return filter;
    }

    private AuthenticationSuccessHandler jsonAuthenticationSuccessHandler() {
        return (request, response, authentication) -> {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            authentication.getPrincipal();
            SecurityUser user = (SecurityUser) authentication.getPrincipal();
            LOG.info("SecurityUser: {}",user);
//            user.setAccessToken(jwtUtil.createAccessToken(user));
//            user.setRefreshToken(jwtUtil.createRefreshToken(user));
            user.setAccessToken(nimbusJoseJwtUtil.createAccessToken(user));
            user.setRefreshToken(nimbusJoseJwtUtil.createRefreshToken(user));
            if (authentication instanceof WechatAppletAuthenticationToken) {
                WechatAppletAuthenticationToken authenticationToken = (WechatAppletAuthenticationToken) authentication;
                 user.setSession_key(authenticationToken.getSession_key());
            }
            response.getWriter().println(objectMapper.writeValueAsString(AppResponse.ok(user)));
            LOG.info("认证成功");
        };
    }

    /**
     * 认证失败实现
     * @return {@link AuthenticationManager}
     */
    private AuthenticationFailureHandler jsonAuthenticationFailureHandler() {

        return (request, response, authenticationException) -> {
            LOG.info("认证失败,原因是: {}",authenticationException);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            AppResponse appResponse;
            if (authenticationException instanceof LockedException) {
                appResponse = AppResponse.setResult(ResponseCode.LOCKED_ACCOUNT);
            } else if(authenticationException instanceof DisabledException) {
                appResponse = AppResponse.setResult(ResponseCode.DISABLED_ACCOUNT);
            } else {
                appResponse = AppResponse.setResult(ResponseCode.AUTHORIZATION).message(authenticationException.getMessage());
            }
            response.getWriter().println(objectMapper.writeValueAsString(appResponse));
        };
    }

    /**
     * 退出登录成功实现
     * @return {@link LogoutSuccessHandler}
     */
    private LogoutSuccessHandler jsonLogoutSuccessHandler() {
        return (request, response, authentication) -> {
            if (authentication != null && authentication.getDetails() != null) {
                request.getSession().invalidate();
            }
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println(objectMapper.writeValueAsString(AppResponse.setResult(ResponseCode.SUCCESS)));
            LOG.info("退出登录成功:{}",authentication);
        };
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        String idForDefault = "bcrypt";
        Map<String,PasswordEncoder> encoders = new HashMap<>();
        encoders.put(idForDefault,new BCryptPasswordEncoder());
        encoders.put("SHA-1",new MessageDigestPasswordEncoder("SHA-1"));
        NoOpPasswordEncoder noOpPasswordEncoder = (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
        encoders.put("noop",noOpPasswordEncoder);
        return new DelegatingPasswordEncoder(idForDefault,encoders);
    }

//    @Bean
//    @ConditionalOnMissingBean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();


//    /**
//     * 认证管理器，登录的时候参数会传给 authenticationManager
//     */
//    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
//    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
//        return authenticationConfiguration.getAuthenticationManager();
//    }



    @Bean
    AuthenticationManager authenticationManager(HttpSecurity httpSecurity) throws Exception {
//        AuthenticationManager authenticationManager = httpSecurity.getSharedObject(AuthenticationManagerBuilder.class)
//                .userDetailsService(usernamePasswordSecurityUserServiceImpl)
//                .passwordEncoder(passwordEncoder())
//                .and()
//                .build();
//        return authenticationManager;
        AuthenticationManagerBuilder authenticationManagerBuilder = httpSecurity.getSharedObject(AuthenticationManagerBuilder.class);
        // authenticationManagerBuilder.eraseCredentials(false);
        // authenticationManagerBuilder.authenticationProvider(restAuthenticationProvider());
        authenticationManagerBuilder.authenticationProvider(emailCodeAuthenticationProvider());
        authenticationManagerBuilder.authenticationProvider(phoneCodeAuthenticationProvider());
        authenticationManagerBuilder.authenticationProvider(wechatAppletAuthenticationProvider());
        return authenticationManagerBuilder.build();
    }

    @Bean
    public RestAuthenticationProvider restAuthenticationProvider() {
        return new RestAuthenticationProvider(usernamePasswordSecurityUserServiceImpl,passwordEncoder());
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        // 设置不启用安全过滤器链的
        return (web) -> web.ignoring().antMatchers( "/druid/**");
    }

//    @Bean
//    public ReloadableResourceBundleMessageSource messageSource() {
//        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
//        // 设置中文配置
//        messageSource.setBasename("classpath:org/springframework/security/messages_zh_CN");
//        return messageSource;
//    }

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
    }

    @Bean
    public EmailCodeAuthenticationFilter emailCodeAuthenticationFilter(AuthenticationManager authenticationManager) {
        EmailCodeAuthenticationFilter filter = new EmailCodeAuthenticationFilter(objectMapper);
        // emailCodeAuthenticationFilter.setAuthenticationSuccessHandler();
        // RestAuthenticationFilter filter = new RestAuthenticationFilter(objectMapper);
        // 登录成功处理
        filter.setAuthenticationSuccessHandler(jsonAuthenticationSuccessHandler());

        // 登陆失败处理
        filter.setAuthenticationFailureHandler(jsonAuthenticationFailureHandler());
        filter.setAuthenticationManager(authenticationManager);
        // emailCodeAuthenticationFilter.setFilterProcessesUrl("/email/login");
        return filter;
    }

    @Bean
    public EmailCodeAuthenticationProvider emailCodeAuthenticationProvider() {
        return new EmailCodeAuthenticationProvider(emailCodeUserDetailsServiceImpl);
    }



    @Bean
    public PhoneCodeAuthenticationFilter phoneCodeAuthenticationFilter(AuthenticationManager authenticationManager) {
        PhoneCodeAuthenticationFilter filter = new PhoneCodeAuthenticationFilter(objectMapper);
        //filter.setAuthenticationSuccessHandler();
        //RestAuthenticationFilter filter = new RestAuthenticationFilter(objectMapper);
        // 登录成功处理
        filter.setAuthenticationSuccessHandler(jsonAuthenticationSuccessHandler());
        // 登陆失败处理
        filter.setAuthenticationFailureHandler(jsonAuthenticationFailureHandler());
        filter.setAuthenticationManager(authenticationManager);
        //filter.setFilterProcessesUrl("/email/login");
        return filter;
    }

    @Bean
    public PhoneCodeAuthenticationProvider phoneCodeAuthenticationProvider() {
        return new PhoneCodeAuthenticationProvider(phoneCodeSecurityUserServiceImpl);
    }



    @Bean
    WechatAppletAuthenticationFilter wechatAppletAuthenticationFilter(AuthenticationManager authenticationManager) {
        WechatAppletAuthenticationFilter filter = new WechatAppletAuthenticationFilter(objectMapper, wXBaseService);
        // 登录成功处理
        filter.setAuthenticationSuccessHandler(jsonAuthenticationSuccessHandler());
        // 登陆失败处理
        filter.setAuthenticationFailureHandler(jsonAuthenticationFailureHandler());
        filter.setAuthenticationManager(authenticationManager);
        //emailCodeAuthenticationFilter.setFilterProcessesUrl("/email/login");
        return filter;
    }

    @Bean
    public WechatAppletAuthenticationProvider wechatAppletAuthenticationProvider() {
        return new WechatAppletAuthenticationProvider(wechatAppletSecurityUserServiceImpl);
    }

    // 默认有效方法为“DELETE”、“GET”、“HEAD”、“OPTIONS”、“PATCH”、“POST”和“PUT”
//    @Bean
//    public StrictHttpFirewall httpFirewall() {
//        StrictHttpFirewall firewall = new StrictHttpFirewall();
//        firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST"));
//        return firewall;
//    }

//    // Expose authentication manager bean
//    @Bean
//    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
//        return authenticationConfiguration.getAuthenticationManager();
//    }

    /**
     * 通过{@link SessionRegistry} 可以获取到当前所有已经登录的用户,根据登录的用户获取它的session状态等等...设置session过期
     * @return
     */
    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }


    //公钥
    private static String publicKeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSja2vpalTbaNg8ChQt133AC6RPD3mpvkPzezb5lw48+AmVyodtJ817Uoi6p+QpkeNyxoivRYEq4Swyf8F18galvstKsR56cjr4oG4XngV0IKNbG+u+/LWqrI8i64PVhn5+wV8L9gwxF/F6tqh4uxoMLK1UAiQ+Pbwk7VTCiVgDAllIk8hAxGKXYN2e2i/ZjeP3jjvyClTYxBKEXWD+EqTflGnbLDs9yqcLgjwcpH+9csY6b7KCIbvFUY/CWJi9n7shRYZZHv3aTJAMbo3VpwDEOpXQXbrZw6mYF7OrHjWVWiMmUHhaVXk73gOx/DbyNp89UOa+t7wyk0A5coPii5wIDAQAB";

    //私钥
    private static String privateKeyStr = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9KNra+lqVNto2DwKFC3XfcALpE8Peam+Q/N7NvmXDjz4CZXKh20nzXtSiLqn5CmR43LGiK9FgSrhLDJ/wXXyBqW+y0qxHnpyOvigbheeBXQgo1sb6778taqsjyLrg9WGfn7BXwv2DDEX8Xq2qHi7GgwsrVQCJD49vCTtVMKJWAMCWUiTyEDEYpdg3Z7aL9mN4/eOO/IKVNjEEoRdYP4SpN+UadssOz3KpwuCPBykf71yxjpvsoIhu8VRj8JYmL2fuyFFhlke/dpMkAxujdWnAMQ6ldBdutnDqZgXs6seNZVaIyZQeFpVeTveA7H8NvI2nz1Q5r63vDKTQDlyg+KLnAgMBAAECggEAYSK3sDdbiMBQMe5nRtbpwsGMXRAvRum1POj9qP2a2F+YYjaiNQec5ALQgjAgTKjPi1kZRsPlkuML3E4xW4dGRncxysxwd561mn9/rRKIHWAerooMSBQRQktCcu/DN34KkaO5NHgHIuKMldowp+kz7/CfLbNKwRdieoxtEYQV+L8rjCYOQUHJMez02G8N4IRkLmY73XlHKQmKBHSuLP/IKNZQbJrmr6Tsjj5NoBKHTSuuEY3QDDqMbZHNh3XYoYOVNnFbqDRjlUx4BLQgLpz5KBOxcV+xP5xyuPZuUlWuS9+3ADeiCptiTO9fDZHxZDHjw0qJo7KBWgLbL+e14KCO8QKBgQDsot+ZVJI9jpOoqPbej7jDDlRSo3zV73IfIHKPiNnbCRJgFUCYXIf6xtOi5+z908T1Cv3e6aQGW8pNUTwco1EMuNgMIPmITMoq6NWzBsbIVw+plIWpOzJQnIPsN8UZAAaxtP+DLrYCgOKDfQa7jKgMlgjWIzIovP7e2oG2eWKTewKBgQDMo207lNmvqIMr8LD3guEjN7GJOVp8yHKbpqMjZwwLoI3BADJDWef0nT/fyB1agfvq80IeA3f6H/ID0qztkNVEqfQWoDrN08Q8pn5K+GGXIirkSivzIM4+mV1SOHDgyoNks8pK2gGmG5bO3SvUlo1Q6MW1pXOrSVwJ0krltvTMhQKBgFIEhdGEQYe6ci1kGuS7FcPtpIZcCfmwm3J0caCUQ0Yq18abtx7X+32NCm+NSVQU4VA5dhKcEnDtwamYvWgDpyTssF1L1JFMZEoJF4CMmbt4iYIyaz1juiW8ifEGx3bJzogrfuA+AXHOsDP40quQrfJm0js+SbVbBE/Dlm/jlKofAoGAUuVQ9nXRyOqGWGJkDZ+i+9UvwdrN4QaCBrN2Gn0/z+X2BlzB/66H2/tnSIuT+Hn3RrHL8sSM8XHHY+0PyByHiA0gp5m4uHA0ai03s77yKXrZzSiOrSp44brWptvePfFLUJvUMoYlbNh4Osw1WSSzkjb5ACBJvvU0p3XciTmX6NECgYEAgoN0GvFls1A+Jhcr9BqVCk+jHcAUhxmQtuQjgGPnUUovrbCc/PtfiM9FKvpxa30SbBjW4t7itfqKLg1zpJcnCOhrhQl7QnnRpGFkRh9STA3xsjsp/dRS5popNR6iGOvEulgobWxK9Ogln61mreZFQSmHVjWPSQQOitJiKWmWxAI=";


    /**
     * @see JWKSource 用于签署访问令牌的实例。
     */
    @Bean
    public JWKSource<SecurityContext> jwkSource() throws NoSuchAlgorithmException, InvalidKeySpecException {
        try {
            KeyPair keyPair = generateRsaKey();
            RSAPublicKey publicKey = getRSAPublicKey(publicKeyStr);
            //RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = getRSAPrivateKey(privateKeyStr);
            //RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();
            JWKSet jwkSet = new JWKSet(rsaKey);
            return new ImmutableJWKSet<>(jwkSet);
        }catch (NoSuchAlgorithmException|InvalidKeySpecException e) {
            throw e;
        }

    }

    private static RSAPublicKey getRSAPublicKey(String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // base64编码的公钥
        byte[] decoded = Base64.getDecoder().decode(publicKeyStr);
        return (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
    }

    private static RSAPrivateKey getRSAPrivateKey(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decoded = Base64.getDecoder().decode(privateKeyStr);
        return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
    }

    /**
     * 启动时生成的带有密钥的实例 {@link KeyPair} 用于创建 {@link JWKSource} 上述内容。
     */
    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }

    /**
     * {@link AuthorizationServerSettings} 配置 Spring Authorization Server 的实例。
     * @see <a href=
     * "https://github.com/spring-projects/spring-authorization-server/commit/c60ae4532f1d745bff6eb793113731aba0493b70">Rename
     * ProviderSettings</a>
     */
    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder().build();
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient defaultRegisteredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                // 客户ID
                .clientId("eatme_client_id")
                // 客户凭证
                .clientSecret("{noop}eatme_client_secret")
                // 客户凭证验证方式
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
                // 授权类型
                //.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                //.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                //.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                //.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
                .authorizationGrantType(new AuthorizationGrantType("wechat_miniprogram"))
                // 授权成功后重定向地址
                .redirectUri("http://127.0.0.1:1401/code")
                // 授权范围
                .scope("snsapi_base")
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                .build();
        return new InMemoryRegisteredClientRepository(defaultRegisteredClient);
    }








}
